<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2024/3/20
 * Time: 11:46
 */

namespace app\queue\timbre;

use app\common\lib\Common;
use app\common\lib\Guzzle;
use app\common\lib\MoyinTts;
use app\common\lib\Puppeteer;
use app\common\lib\RedisQueue;
use app\common\lib\TencentAsr;
use app\common\lib\TencentIvld;
use app\exception\IndexException;
use app\model\moyin\GenerateTimbreLogModel;
use app\model\novel\NovelChapterPartModel;
use app\model\plan\NovelChapterPartOverseaModel;
use app\model\plan\PromotionPlanModel;
use app\model\plan\PromotionPlanOverseaModel;
use app\model\redis\RedisQueueModel;
use app\model\user\UserNovelChapterPartModel;
use app\model\user\UserPromotionPlanModel;
use app\model\user\UserPromotionVideoModel;
use app\model\video\AsyncUploadVideoIvldModel;
use support\Cache;
use Webman\RedisQueue\Consumer;
use app\common\lib\TencentCos;

class GenerateTimbre  implements Consumer
{
    // 要消费的队列名
    public $queue = 'generateTimbre';

    // 连接名，对应 plugin/webman/redis-queue/redis.php 里的连接`
    public $connection = 'default';

    protected $resultData = [];

    // 消费
    public function consume($data)
    {
        Common::initQueueConfig();

        $queue = RedisQueueModel::getInstance()->find($data['queueid']);
        $queue->exec_time = date('Y-m-d H:i:s');
        $queue->save();

        try{

            $result = $this->handle($data);

            RedisQueue::getInstance()->saveQueue($this->queue,$data,$result);
        }catch (\Throwable $e){
            RedisQueue::getInstance()->saveQueue($this->queue,$data,['error'=>$e->getMessage()]);
            Common::queueExecptionReport($queue,$data,$e);
        }
    }

    protected function handle($data)
    {
        switch ($data['source']){
            case 'generate_work':
                return  $this->generatedWorkTimbre($data);
                break;
            case 'generate_work_card_content':
                return  $this->generatedWorkCardContentTimbre($data);
                break;
            case 'plan_part':
                return $this->generatedPlanTimbre($data);
                break;
            case 'plan_part_oversea':
                return $this->generatedPlanOverseaTimbre($data);
                break;
        }

    }

    protected function generatedWorkTimbre($data)
    {
        $userPlan = UserPromotionPlanModel::getInstance()->find($data['user_planid']);
        $where = ['user_planid'=>$data['user_planid']];
        $userPlanParts = UserNovelChapterPartModel::getInstance()->getWhere($where)->orderBy('number','asc')->get();

        $result = $this->generatedTimbre($userPlan,$userPlanParts,'generate_work');
        return ['success'];
    }

    /**
     * 卡片风格-卡片简介内容配音
     * @param $data
     * @return string[]
     * @throws IndexException
     */
    protected function generatedWorkCardContentTimbre($data): array
    {
        $userPlan = UserPromotionPlanModel::getInstance()->find($data['user_planid']);
        $timbreid = \app\model\moyin\TimbreModel::getInstance()->getWhere(['id' => $userPlan['timbreid']])->value('timbreid');
        $timbre = \app\model\moyin\TimbreModel::getInstance()->getWhere(['id' => $userPlan['timbreid']])->first();
        if ($timbre == false) {
            throw new IndexException(4020, '音色不存在');
        }

        $content = !empty($userPlan->card_content) ? $userPlan->card_content : '';
        if (!$content) {
            throw new IndexException(4020, '卡片简介总结内容不能为空');
        }

        try {

            $volume = round($userPlan['timbre_volume'] / 10, 1);
            $volume = $volume >= 0.1 && $volume <= 100 ? $volume : 1.0;
            $speed = round($userPlan['speak_speed'] / 10, 1);
            $speed = $speed >= 0.5 && $speed <= 2 ? $speed : 1.0;

            $unicode = md5($timbreid . '-' . $speed . '-' . $volume . '-' . $content);
            $first = GenerateTimbreLogModel::getInstance()->getWhere(['unicode' => $unicode])->first();
            if ($first == false || empty(json_decode($first->word_content, true))) {
                try {
                    $res = $this->generateCardContentTimbre($userPlan, $volume, $speed, $timbreid, $content);
                } catch (\Throwable $e) {
                    //如果失败再调一次
                    sleep(1);
                    $res = $this->generateCardContentTimbre($userPlan, $volume, $speed, $timbreid, $content);
                }

                $insert = [
                    'unicode' => $unicode,
                    'timbreid' => $timbreid,
                    'name' => $timbre['name'],
                    'speak_speed' => $speed,
                    'timbre_volume' => $volume,
                    'word_content' => $res['timbre_voice_info'],
                    'platform' => 'moyin',
                    'source_id' => $userPlan['id'],
                    'source_table' => UserPromotionPlanModel::getInstance()->getTable(),
                    'content' => $content,
                    'timbre_voice_url' => $res['timbre_voice_url'],
                ];
                GenerateTimbreLogModel::getInstance()->insert($insert);

            } else {
                $userPlan->card_dup = $first->timbre_voice_url;
                $userPlan->save();
            }

        } catch (\Throwable $e) {
            throw new IndexException(4020, '卡片内容简介总结语音合成失败: 内容：' . $content . '。 错误信息：' . $e->getMessage());
        }


        return ['success'];
    }

    protected function generatedPlanTimbre($data)
    {
        $plan = PromotionPlanModel::getInstance()->getWhere(['id'=>$data['planid']])->first();
        $where = ['planid'=>$data['planid'],'batch'=>$data['batch'],'isdel'=>0];
        $parts = NovelChapterPartModel::getInstance()->getWhere($where)->orderBy('number','asc')->get();

        $result = $this->generatedTimbre($plan,$parts,'plan_part');
        return ['success'];
    }

    protected function generatedPlanOverseaTimbre($data)
    {
        $plan = PromotionPlanOverseaModel::getInstance()->getWhere(['id'=>$data['planid']])->first();
        $where = ['planid'=>$data['planid'],'batch'=>$data['batch'],'isdel'=>0];
        $parts = NovelChapterPartOverseaModel::getInstance()->getWhere($where)->orderBy('number','asc')->get();

        $result = $this->generatedTimbre($plan,$parts,'plan_part_oversea');
        return ['success'];
    }

    protected function generatedTimbre($plan,$parts,$type){
        $timbreid = \app\model\moyin\TimbreModel::getInstance()->getWhere(['id'=>$plan['timbreid']])->value('timbreid');
        $timbre = \app\model\moyin\TimbreModel::getInstance()->getWhere(['id'=>$plan['timbreid']])->first();
        if($timbre==false){
            throw new IndexException(4020,'音色不存在');
        }

        foreach ($parts as $val){
            $content = $val['content'];
            if($content==false){
                throw new IndexException(4020,'段落内容不能为空');
            }

            if(strpos($type,'oversea')!==false || (isset($plan['plan_type']) && in_array($plan['plan_type'],[4]))){
                //内容必须包含字母或数字，不能只有符号
                if(preg_match('/[a-z|A-Z|0-9]+/',$content)==false){
                    continue;
                }
            }else{
                //如果没有中文过滤掉该片段
                $pattern = '/[\x{4e00}-\x{9fa5}]+/u';
                $res = preg_match_all($pattern, $content, $matches);
                if($res==false){
                    continue;
                }
            }

            try{
                //$subTitles = !empty($val['subtitle']) ? json_decode($val['subtitle'], true) : [];
                //                $content = $subTitles ? implode(',',$subTitles) : '';

                $volume = round($plan['timbre_volume']/10,1);
                $volume = $volume>=0.1 && $volume<=100 ? $volume : 1.0;
                $speed = round($plan['speak_speed']/10,1);
                $speed = $speed>=0.5 && $speed<=2 ? $speed : 1.0;

                $unicode = md5($timbreid.'-'.$speed.'-'.$volume.'-'.$content);
                $first = GenerateTimbreLogModel::getInstance()->getWhere(['unicode'=>$unicode])->first();
                if($first==false || empty(json_decode($first->word_content, true))){
                    try{
                        $val = $this->generateTimbre($val,$volume,$speed,$timbreid,$content);
                    }catch (\Throwable $e){
                        //如果失败再调一次
                        sleep(1);
                        $val = $this->generateTimbre($val,$volume,$speed,$timbreid,$content);
                    }

                    //保存生成记录
                    $sourceTableMap = [
                        'generate_work'=>UserPromotionPlanModel::getInstance()->getTable(),
                        'plan_part'=>PromotionPlanModel::getInstance()->getTable(),
                        'plan_part_oversea'=>PromotionPlanOverseaModel::getInstance()->getTable(),
                    ];
                    $insert = [
                        'unicode'=>$unicode,
                        'timbreid'=>$timbreid,
                        'name'=>$timbre['name'],
                        'speak_speed'=>$speed,
                        'timbre_volume'=>$volume,
                        'word_content'=>$val->timbre_voice_info,
                        'platform'=>'moyin',
                        'source_id'=>$plan['id'],
                        'source_table'=>$sourceTableMap[$type]??'',
                        'content'=>$content,
                        'timbre_voice_url'=>$val->timbre_voice_url,
                    ];
                    GenerateTimbreLogModel::getInstance()->insert($insert);

                }else{
                    $val->timbre_voice_url = $first->timbre_voice_url;
                    $val->timbre_voice_info = $first->word_content;

                    $wordContent = json_decode($first->word_content, true);
                    if($wordContent){
                        $subtitles = array_values(array_filter(array_column($wordContent,'content')));
                        $val->subtitle = json_encode($subtitles,256);
                    }

                    $val->save();
                }

            }catch (\Throwable $e){
                if($type=='generate_work'){
                    throw new IndexException(4020,'语音合成失败: 内容：'.$content.'。 错误信息：'.$e->getMessage());
                }
            }

            usleep(300000);
        }

        return true;
    }

    protected function generateTimbre($val,$volume,$speed,$timbreid,$content)
    {
        $option = [
            'volume'=>$volume,
            'speed'=>$speed,
            'speaker'=>$timbreid,
        ];
        $result = timbreTextToVoice($content,$option);
        $val->timbre_voice_url = $result['voice_url'];
        $val->timbre_voice_info = json_encode($result['srt_address_data'],256);

        $subtitles = array_values(array_filter(array_column($result['srt_address_data'],'content')));
        $val->subtitle = json_encode($subtitles,256);
        $val->save();

       return $val;
    }


    /**
     * 卡片简介总结语音配音
     * @param $userPlan
     * @param $volume
     * @param $speed
     * @param $timbreid
     * @param $content
     * @return mixed
     * @throws IndexException
     * @throws \Throwable
     */
    protected function generateCardContentTimbre($userPlan,$volume,$speed,$timbreid,$content)
    {
        $option = [
            'volume'=>$volume,
            'speed'=>$speed,
            'speaker'=>$timbreid,
        ];
        $result = timbreTextToVoice($content,$option);
        $userPlan->card_dub = $result['voice_url'];
        $userPlan->save();
       return ['timbre_voice_url'=>$result['voice_url'], 'timbre_voice_info'=>json_encode($result['srt_address_data'],256)];
    }

    // 消费失败回调
    /*
    $package = [
        'id' => 1357277951, // 消息ID
        'time' => 1709170510, // 消息时间
        'delay' => 0, // 延迟时间
        'attempts' => 2, // 消费次数
        'queue' => 'send-mail', // 队列名
        'data' => ['to' => 'tom@gmail.com', 'content' => 'hello'], // 消息内容
        'max_attempts' => 5, // 最大重试次数
        'error' => '错误信息' // 错误信息
    ]
    */
    public function onConsumeFailure(\Throwable $e, $package)
    {
//        echo "consume failure\n";
//        echo $e->getMessage() . "\n";
//        // 无需反序列化
//        var_export($package);

        RedisQueue::getInstance()->saveQueue($this->queue,$package['data'],['error'=>$e->getMessage()]);
    }

}